package grex.genes;

/**
 * <p>Title: </p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2003</p>
 * <p>Company: </p>
 * @author not attributable
 * @version 1.0
 */
import grex.BNFException;
import grex.ErrorManager;
import grex.Options;
import grex.Prediction;
import grex.PredictionContainer;

import java.util.ArrayList;

public class FuzzyVery extends Gene implements IFuzzyNode, IContinuousOperator {

    private static final int NROFCILDREN = 2;
    private int varNr = -1;
    private int count = 0;
    double[] mSums;

    public FuzzyVery() throws BNFException {
        super(NROFCILDREN);
    }

    public synchronized void execute(Gene parent, PredictionContainer data, int mode) throws GeneException {
        this.parent = parent;
        initVarNr();

        for (Prediction p : data.values()) {
            ArrayList<FuzzyMembershipClassPair> mValues = fuzzit(p.getInstance(), 1);
            if (ops.getPROBLEM_TYPE() == Options.CLASSIFICATION) {
                mSums = new double[environment.getNrOfTargetCategories()];
            } else {
                mSums = new double[1];
            }

            double mVal = 0;
            int classIndex = 0;
            for (FuzzyMembershipClassPair mc : mValues) {
                mSums[((int) mc.classValue)] += mc.membership;
            }

            /*for (int i = 0; i < mSums.length; i++) {
                if (mSums[i] > mVal) {
                    mVal = mSums[i];
                    classIndex = i;
                }
            }*/
            p.setPrediction(-1);
            //p.setProb(mVal);
            p.setSupport(mSums);

            p.setLeaf(this);
        }
    }

    private void initVarNr() throws GeneException {
        if (varNr == -1) {
            varNr = environment.getRandomContiousColumnIndex();
        }
    }

    public ArrayList<FuzzyMembershipClassPair> fuzzit(double[] instance, double membershipValue) throws GeneException {
        initVarNr();
        Gene left = getChildren()[0];
        Gene right = getChildren()[1];
        ArrayList<FuzzyMembershipClassPair> lResult;
        ArrayList<FuzzyMembershipClassPair> rResult;
        double leftMembershipValue = membershipValue * (1 - Math.pow(instance[varNr],2));
        double rightMembershipValue = membershipValue * (Math.pow(instance[varNr],2));
        if (left instanceof IFuzzyNode) {
            lResult = ((IFuzzyNode) left).fuzzit(instance, leftMembershipValue);
        } else {//TargetPrediction
            lResult = new ArrayList<FuzzyMembershipClassPair>();
            lResult.add(new FuzzyMembershipClassPair(((FuzzyTarget) left).getValue(), leftMembershipValue));
        }

        if (right instanceof IFuzzyNode) {
            rResult = ((IFuzzyNode) right).fuzzit(instance, rightMembershipValue);
        } else {//TargetPrediction
            rResult = new ArrayList<FuzzyMembershipClassPair>();
            rResult.add(new FuzzyMembershipClassPair(((FuzzyTarget) right).getValue(), rightMembershipValue));
        }

        lResult.addAll(rResult);
        return lResult;
    }

    public void setVarNr(int varNr) {
        this.varNr = varNr;
    }

    public int getVarNr() {
        return varNr;
    }

    public Object clone() {
    	FuzzyVery newFuzzySet;
        try {
            newFuzzySet = new FuzzyVery();
            newFuzzySet.setVarNr(varNr);
            newFuzzySet.setOptions(ops);
            newFuzzySet.setEnvironment(environment);
            cloneChildren(newFuzzySet);
            newFuzzySet.setParent(parent);
            newFuzzySet.mSums = mSums;
        } catch (grex.BNFException e) {
            ErrorManager.getInstance().reportError(e);
            return null;
        }
        return newFuzzySet;
    }

    public String toString() {
        try {
            if (varNr == -1) {
                varNr = environment.getRandomContiousColumnIndex();
            }
            return "Very(" + environment.getVariableNames()[varNr]+ ")";
        } catch (GeneException ex) {
            ErrorManager.getInstance().reportError(ex);
        }
        return environment.getVariableNames()[varNr];
    }

    public double getProb() {
        this.getType();
        return 0;
    }

    public double getLowProb() {
        return 0;
    }

    public int getCount() {
        return count;
    }
}

